package org.mirrentools.remoteattendance;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.mirrentools.remoteattendance.common.Requests;
import org.mirrentools.remoteattendance.common.StringUtil;
import org.mirrentools.remoteattendance.options.Options;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.Optional;

/**
 * 应用主窗口
 * @author <a href="https://mirrentools.org">Mirren</a>
 */
public class MainApplication extends Application {
  public static void main(String[] args) {
    System.setProperty("vertx.disableDnsResolver", "true");
    launch();
  }

  /**
   * Vert.x实例
   */
  public static final String USER_DIR;
  /**
   * Vert.x实例
   */
  public static final Vertx VERTX;
  /**
   * 系统配置文件
   */
  public static final Options OPTIONS;
  /**
   * 网络请求客户端
   */
  public static final WebClient WEB_CLIENT;

  static {
    String root = System.getProperty("user.dir");
    String userDir = root;
    VERTX = Vertx.vertx();
    Path path = Paths.get(root, "data", "config.json");
    byte[] bs;
    JsonObject config = null;
    try {
      bs = Files.readAllBytes(path);
      config = new JsonObject(new String(bs));
      String screenshotFolder = config.getString("screenshotFolder");
      if (!StringUtil.isNullOrEmpty(screenshotFolder) && !Objects.equals("user.dir", screenshotFolder)) {
        userDir = screenshotFolder;
      }
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(0);
    }
    USER_DIR = userDir;
    OPTIONS = Options.from(config);
    WebClientOptions clientOptions = new WebClientOptions();
    clientOptions.setMaxPoolSize(OPTIONS.maxWebClientSize());
    WEB_CLIENT = WebClient.create(VERTX, clientOptions);
  }

  @Override
  public void start(Stage stage) {
    try {
      Platform.setImplicitExit(false);
      stage.setOnCloseRequest(event -> closeHandler(stage, event));
      StackPane pane = new StackPane();
      Label loading = new Label("正在加载中...");
      pane.getChildren().add(loading);
      stage.setScene(new Scene(pane, 1024, 768));
      checkToken(res -> {
        if (res.succeeded()) {
          Logger.log("初始化考勤系统->检查权限-->通过!");
          Platform.runLater(() -> {
            try {
              FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("hello-view.fxml"));
              Scene scene = new Scene(fxmlLoader.load(), 1024, 768);
              stage.setScene(scene);
            } catch (Exception e) {
              loading.setText("初始化考勤系统失败,请联系管理员!\n错误信息:" + e);
              String tips = "执行初始化考勤系统->检查用户权限-->失败!";
              Logger.log(tips, e);
              showAlert(tips, 2);
            }
          });
        } else {
          Logger.log("初始化考勤系统->检查权限-->不通过!");
          Platform.runLater(() -> loading.setText("初始化考勤系统失败,请联系管理员!\n错误信息:" + res.cause()));
          String tips = "执行初始化考勤系统->检查用户权限-->失败!";
          Logger.log(tips, res.cause());
          showAlert(tips, 2);
        }
      });
      stage.setTitle("考勤系统");
      URL url = MainApplication.class.getResource("icon.png");
      if (url != null) {
        stage.getIcons().add(new Image(url.toURI().toString()));
      }
      stage.show();
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }

  /**
   * 检查用户的Token是否正确
   *
   * @param handler 结果处理器,成功则代表检查通过,异常则代表请求不通过
   */
  public static void checkToken(Handler<AsyncResult<Integer>> handler) {
    Future<JsonObject> future = Requests.get(Requests.PATH_CHECK_TOKEN);
    future.onSuccess(res -> handler.handle(Future.succeededFuture(1)));
    future.onFailure(e -> handler.handle(Future.failedFuture(e)));
  }

  /**
   * 关闭系统的事件
   *
   * @param stage 舞台
   * @param event 窗口时间
   */
  public void closeHandler(Stage stage, WindowEvent event) {
    Alert alert = new Alert(Alert.AlertType.NONE);
    alert.setContentText("请选择操作:\n\n");
    ButtonType cancel = new ButtonType("取消", ButtonType.CANCEL.getButtonData());
    ButtonType close = new ButtonType("关闭系统", ButtonType.CLOSE.getButtonData());
    ButtonType tray = new ButtonType("隐藏到托盘", ButtonType.APPLY.getButtonData());
    alert.getButtonTypes().setAll(cancel, close, tray);
    Optional<ButtonType> type = alert.showAndWait();
    if (Objects.equals(close, type.orElse(cancel))) {
      Platform.runLater(() -> System.exit(0));
    } else {
      if (tray == type.orElse(cancel)) {
        hideWindow(stage);
      }
      event.consume();
    }
  }


  /**
   * 隐藏系统到托盘
   *
   * @param primaryStage stage
   */
  public void hideWindow(Stage primaryStage) {
    try {
      SystemTray tray = SystemTray.getSystemTray();
      TrayIcon[] icons = tray.getTrayIcons();
      if (icons == null || icons.length == 0) {
        URL url = MainApplication.class.getResource("icon.png");
        java.awt.Image image = Toolkit.getDefaultToolkit().getImage(url);
        // 系统托盘图标
        TrayIcon icon = new TrayIcon(image);
        icon.setImageAutoSize(true);
        icon.setToolTip("显示系统");
        icon.addMouseListener(new java.awt.event.MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            Platform.runLater(() -> {
              if (primaryStage.isIconified()) {
                primaryStage.setIconified(false);
              }
              if (!primaryStage.isShowing()) {
                primaryStage.show();
              }
              primaryStage.toFront();
            });
          }
        });
        tray.add(icon);
      }
      Platform.runLater(() -> {
        if (SystemTray.isSupported()) {
          primaryStage.hide();
        } else {
          primaryStage.setIconified(true);
        }
      });
    } catch (Exception ex) {
      String tips = "执行隐藏系统到托盘-->失败!";
      Logger.log(tips, ex);
      showAlert(tips, 2);
    }
  }

  /**
   * 显示消息弹窗
   *
   * @param msg  信息
   * @param type 弹窗的类型,0=普通提醒,1=警告提醒,2=异常
   */
  public static void showAlert(String msg, int type) {
    Platform.runLater(() -> {
      if (type == 1) {
        Alert alert = new Alert(Alert.AlertType.WARNING);
        alert.setContentText(msg);
        alert.show();
      } else if (type == 2) {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        ButtonType cancel = new ButtonType("取消", ButtonType.CANCEL.getButtonData());
        ButtonType copy = new ButtonType("复制日志信息", ButtonType.NEXT.getButtonData());
        alert.getButtonTypes().clear();
        alert.getButtonTypes().add(copy);
        alert.getButtonTypes().add(cancel);
        alert.setContentText(msg);
        Optional<ButtonType> buttonType = alert.showAndWait();
        if (Objects.equals(copy, buttonType.orElse(cancel))) {
          String info = Logger.info();
          Clipboard cb = Clipboard.getSystemClipboard();
          ClipboardContent content = new ClipboardContent();
          content.putString(info);
          cb.setContent(content);
        }
      } else {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText(msg);
        alert.show();
      }
    });
  }
}
